package com.interview.javabase.thread;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * @description:
 * @author: zhangshuguang@vichain.com
 * @date: 2019/06/14 13:49
 */
public class Demo8 {

    // 主内存atomicInteger初始值为1
    public static AtomicInteger atomicInteger = new AtomicInteger(100);

    // 主内存共享变量，初始值为1，版本号为1
    private static AtomicStampedReference<Integer> atomicStampedReference = new
            AtomicStampedReference<>(100, 1);

    public static void main(String[] args) throws InterruptedException {

//        System.out.println("============== 演示 CAS =============");
//        // t1线程计划将值改为10，先休眠2s,再比较交换 发现主物理内存的值已经变成了102 而自己期望值为100所以修改失败
//        new Thread(() -> {
//            try { TimeUnit.SECONDS.sleep(2);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            System.out.println("当前线程: "+Thread.currentThread().getName()+"比较交换结果："
//                    +atomicInteger.compareAndSet(100, 101)+" 现在值为："+atomicInteger.get());
//        },"t1").start();
//
//        // t2线程计划将值改为10，不休眠 发现主物理内存的值已经变成了100 而自己期望值为100所以修改成功
//        new Thread(() -> {
//            System.out.println("当前线程: "+Thread.currentThread().getName()+"比较交换结果："
//                    +atomicInteger.compareAndSet(100, 102)+" 现在值为："+atomicInteger.get());
//        },"t2").start();

        System.out.println("============== 演示 CAS ABA问题=============");

        // t1进行ABA操作
        new Thread(() -> {
            atomicInteger.compareAndSet(100,102);
            atomicInteger.compareAndSet(102,100);
            System.out.println(Thread.currentThread().getName()+" 最新值为："+atomicInteger.get());
        },"t1").start();

        // t2进行CAS操作
        new Thread(() -> {
            try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
            boolean b = atomicInteger.compareAndSet(100, 2019);
            System.out.println(Thread.currentThread().getName() +"是否修改成功"+b+" 最新值为："+atomicInteger.get());
        },"t2").start();

        try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
        System.out.println("============== 解决 CAS ABA问题=============");

        new Thread(() -> {
            // 第一次拿到的版本号
            int stamp = atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName()+" 第1次版本号："+stamp+" 值为："+atomicStampedReference.getReference());

            try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }

            atomicStampedReference.compareAndSet(100,102,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);
            System.out.println(Thread.currentThread().getName()+" 第2次版本号："+atomicStampedReference.getStamp()+" 值为："+atomicStampedReference.getReference());
            atomicStampedReference.compareAndSet(102,100,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);
            System.out.println(Thread.currentThread().getName()+" 第3次版本号："+atomicStampedReference.getStamp()+" 值为："+atomicStampedReference.getReference());
        },"t3").start();

        new Thread(() -> {
            // 第一次拿到的版本号
            int stamp = atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName()+" 第1次版本号："+stamp+" 值为："+atomicStampedReference.getReference());
            // 休眠3s,确保t3执行完ABA操作
            try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
            // t2将时间戳改为了3,cas失败
            boolean b = atomicStampedReference.compareAndSet(100, 209, stamp, stamp + 1);
            System.out.println(Thread.currentThread().getName()+"是否修改成功"+b+" 当前最新版本号："+atomicStampedReference.getStamp()+" 最新值为："+atomicStampedReference.getReference());
        },"t4").start();
    }

}
